home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / pgp20src.zip / FILEIO.C < prev    next >
C/C++ Source or Header  |  1992-08-31  |  24KB  |  985 lines

  1. /*    fileio.c  - I/O routines for PGP.
  2.     PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
  3.  
  4.     (c) Copyright 1990-1992 by Philip Zimmermann.  All rights reserved.
  5.     The author assumes no liability for damages resulting from the use
  6.     of this software, even if the damage results from defects in this
  7.     software.  No warranty is expressed or implied.
  8.  
  9.     All the source code Philip Zimmermann wrote for PGP is available for
  10.     free under the "Copyleft" General Public License from the Free
  11.     Software Foundation.  A copy of that license agreement is included in
  12.     the source release package of PGP.  Code developed by others for PGP
  13.     is also freely available.  Other code that has been incorporated into
  14.     PGP from other sources was either originally published in the public
  15.     domain or was used with permission from the various authors.  See the
  16.     PGP User's Guide for more complete information about licensing,
  17.     patent restrictions on certain algorithms, trademarks, copyrights,
  18.     and export controls.  
  19.  
  20.     Modified 16 Apr 92 - HAJK
  21.     Mods for support of VAX/VMS file system
  22. */
  23.  
  24. #include <ctype.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #if defined(UNIX)
  29. #include <sys/stat.h>
  30. #if !defined(NeXT)
  31. #include <unistd.h>
  32. #endif
  33. #endif
  34. #include "random.h"
  35. #include "mpilib.h"
  36. #include "mpiio.h"
  37. #include "fileio.h"
  38. #include "language.h"
  39. #include "pgp.h"
  40. #ifdef MSDOS
  41. #include <io.h>
  42. #include <fcntl.h>
  43. #endif
  44.  
  45. /* 1st character of temporary file extension */
  46. #define    TMP_EXT    '$'        /* extensions are '.$##' */
  47.  
  48. /* The PGPPATH environment variable */
  49.  
  50. char PGPPATH[] = "PGPPATH";
  51.  
  52. /* Disk buffers, used here and in crypto.c */
  53. byte textbuf[DISKBUFSIZE];
  54. static byte textbuf2[2*DISKBUFSIZE];
  55.  
  56. boolean file_exists(char *filename)
  57. /*    Returns TRUE iff file exists. */
  58. {
  59. #ifdef UNIX
  60. #ifndef F_OK
  61. #define F_OK    0
  62. #endif
  63.     return(access(filename, F_OK) == 0);
  64. #else
  65.     FILE *f;
  66.     /* open file f for read, in binary (not text) mode...*/
  67.     if ((f = fopen(filename,"rb")) == NULL)
  68.         return(FALSE);
  69.     fclose(f);
  70.     return(TRUE);
  71. #endif
  72. }    /* file_exists */
  73.  
  74.  
  75. boolean file_ok_write(char *filename)
  76. /*    Returns TRUE iff file can be opened for writing.
  77.     Does not harm file!
  78. */
  79. {    FILE *f;
  80.     if (file_exists (filename))
  81.         return(TRUE);
  82.     if ((f = fopen(filename,"wb")) == NULL)
  83.         return(FALSE);
  84.     fclose(f);
  85.     remove(filename);
  86.     return(TRUE);
  87. }    /* file_ok_write */
  88.  
  89. boolean is_regular_file(char *filename)
  90. {
  91. #ifdef S_ISREG
  92.     struct stat st;
  93.     return(stat(filename, &st) != -1 && S_ISREG(st.st_mode));
  94. #else
  95.     return TRUE;
  96. #endif
  97. }
  98.  
  99. int wipeout(FILE *f)
  100. {    /*    Completely overwrite and erase file, so that no sensitive
  101.         information is left on the disk.
  102.         NOTE:  File MUST be open for read/write.
  103.     */
  104.  
  105.     long flength;
  106.     int count = 0;
  107.  
  108.     fseek(f, 0L, SEEK_END);
  109.     flength = ftell(f);
  110.     rewind(f);
  111.  
  112.     fill0(textbuf, sizeof(textbuf));
  113.     while (flength > 0L)
  114.     {    /* write zeros to the whole file... */
  115.         if (flength < (word32) DISKBUFSIZE)
  116.             count = (int)flength;
  117.         else
  118.             count = DISKBUFSIZE;
  119.         fwrite(textbuf,1,count,f);
  120.         flength -= count;
  121.     }
  122.     rewind(f);    /* maybe this isn't necessary */
  123.     return(0);    /* normal return */
  124. }    /* wipeout */
  125.  
  126.  
  127. int wipefile(char *filename)
  128. {    /*    Completely overwrite and erase file, so that no sensitive
  129.         information is left on the disk.
  130.     */
  131.     FILE *f;
  132.     /* open file f for read/write, in binary (not text) mode...*/
  133. #ifdef VMS
  134.     if ((f = fopen(filename,"rb+","ctx=stm")) == NULL)
  135. #else
  136.     if ((f = fopen(filename,"rb+")) == NULL)
  137. #endif
  138.         return(-1);    /* error - file can't be opened */
  139.     wipeout(f);
  140.     fclose(f);
  141.     return(0);    /* normal return */
  142. }    /* wipefile */
  143.  
  144. char    *file_tail (char *filename)
  145. /*    Returns the after-slash part of filename.  Also skips backslashes,
  146.  *  colons, and right brackets.    */
  147. {
  148.     char *bslashPos = strrchr(filename, '\\');/* Find last bslash in filename */
  149.     char *slashPos = strrchr(filename, '/');/* Find last slash in filename */
  150.     char *colonPos = strrchr(filename, ':');
  151.     char *rbrakPos = strrchr(filename, ']');
  152.  
  153.     if (!slashPos  ||  bslashPos > slashPos)
  154.         slashPos = bslashPos;
  155.     if (!slashPos  ||  colonPos > slashPos)
  156.         slashPos = colonPos;
  157.     if (!slashPos  ||  rbrakPos > slashPos)
  158.         slashPos = rbrakPos;
  159.     return( slashPos?(slashPos+1):filename );
  160. }
  161. /* Define BSLASH for machines that use backslash, FSLASH for machines
  162.  * that use forward slash as separators.
  163.  */
  164.  
  165. #ifdef MSDOS
  166. #define    BSLASH
  167. #endif
  168. #ifdef ATARI
  169. #define BSLASH
  170. #endif
  171. #ifdef UNIX
  172. #define FSLASH
  173. #define MULTIPLE_DOTS
  174. #endif
  175. #ifdef AMIGA
  176. #define FSLASH
  177. #define MULTIPLE_DOTS
  178. #endif
  179.  
  180. boolean has_extension(char *filename, char *extension)
  181. {    /* return TRUE if extension matches the end of filename */
  182.     int lf = strlen(filename);
  183.     int lx = strlen(extension);
  184.  
  185.     if (lf <= lx)
  186.         return(FALSE);
  187.     return(!strcmp(filename + lf - lx, extension));
  188. }
  189.  
  190. boolean is_tempfile(char *path)
  191. {    /* return TRUE if path is a filename created by tempfile() */
  192.     char *p;
  193.     
  194.     return((p = strrchr(path, '.')) != NULL &&
  195.             p[1] == TMP_EXT && strlen(p) == 4);
  196. }
  197.  
  198. boolean no_extension(char *filename)
  199. /*    Returns TRUE if user left off file extension, allowing default. */
  200. {
  201. #ifdef MULTIPLE_DOTS    /* filename can have more than one dot */
  202.     if (has_extension(filename, CTX_EXTENSION) ||
  203.         has_extension(filename, ASC_EXTENSION) ||
  204.         has_extension(filename, PGP_EXTENSION) ||
  205.         has_extension(filename, SIG_EXTENSION) ||
  206.         is_tempfile(filename))
  207.         return(FALSE);
  208.     else
  209.         return(TRUE);
  210. #else
  211. #ifdef BSLASH
  212.     char *slashPos = strrchr(filename, '\\');    /* Find last slash in filename */
  213.  
  214.     /* Look for the filename after the last slash if there is one */
  215.     return(strchr((slashPos != NULL ) ? slashPos : filename, '.') == NULL);
  216. #else
  217. #ifdef FSLASH
  218.     char *slashPos = strrchr(filename, '/');    /* Find last slash in filename */
  219.  
  220.     /* Look for the filename after the last slash if there is one */
  221.     return(strchr((slashPos != NULL ) ? slashPos : filename, '.') == NULL);
  222. #else
  223. #ifdef VMS
  224.     char *slashPos = strrchr(filename,']');        /* Locate end of directory spec */
  225.  
  226.     /* Look for last period in filename */
  227.     return(strrchr((slashPos != NULL) ? slashPos : filename, '.') == NULL );
  228. #else
  229.     return( (strrchr(filename,'.')==NULL) ? TRUE : FALSE );
  230. #endif /* VMS */
  231. #endif /* FSLASH */
  232. #endif /* BSLASH */
  233. #endif /* MULTIPLE_DOTS */
  234. }    /* no_extension */
  235.  
  236.  
  237. void drop_extension(char *filename)
  238. {    /* deletes trailing ".xxx" file extension after the period. */
  239.     if (!no_extension(filename))
  240.         *strrchr(filename,'.') = '\0';
  241. }    /* drop_extension */
  242.  
  243.  
  244. void default_extension(char *filename, char *extension)
  245. {    /* append filename extension if there isn't one already. */
  246.     if (no_extension(filename))
  247.         strcat(filename,extension);
  248. }    /* default_extension */
  249.  
  250. #ifndef MAX_NAMELEN
  251. #if defined(AMIGA) || defined(NeXT)
  252. #define    MAX_NAMELEN    255
  253. #endif
  254. #endif
  255.  
  256. void truncate_name(char *path, int ext_len)
  257. {    /* truncate the filename so that an extension can be tacked on. */
  258. #ifdef UNIX        /* for other systems this is a no-op */
  259.     char dir[MAX_PATH], *p;
  260.     int namemax;
  261.  
  262. #ifdef MAX_NAMELEN    /* overrides the use of pathconf() */
  263.     namemax = MAX_NAMELEN
  264. #else
  265. #ifdef _PC_NAME_MAX
  266.     strcpy(dir, path);
  267.     if ((p = strrchr(dir, '/')) == NULL)
  268.         strcpy(dir, ".");
  269.     else
  270.     {    if (p == dir)
  271.             ++p;
  272.         *p = '\0';
  273.     }
  274.     if ((namemax = pathconf(dir, _PC_NAME_MAX)) <= ext_len)
  275.         return;
  276. #else
  277.     namemax = 14;
  278. #endif
  279. #endif /* MAX_NAMELEN */
  280.  
  281.     if ((p = strrchr(path, '/')) == NULL)
  282.         p = path;
  283.     else
  284.         ++p;
  285.     if (strlen(p) > namemax - ext_len)
  286.     {
  287.         if (verbose)
  288.             fprintf(pgpout, "Truncating filename '%s' ", path);
  289.         p[namemax - ext_len] = '\0';
  290.         if (verbose)
  291.             fprintf(pgpout, "to '%s'\n", path);
  292.     }
  293. #endif /* UNIX */
  294. }
  295.  
  296. void force_extension(char *filename, char *extension)
  297. {    /* change the filename extension. */
  298.     drop_extension(filename);    /* out with the old */
  299.     truncate_name(filename, strlen(extension));
  300.     strcat(filename,extension);    /* in with the new */
  301. }    /* force_extension */
  302.  
  303.  
  304. boolean getyesno(char default_answer)
  305. /*    Get yes/no answer from user, returns TRUE for yes, FALSE for no. 
  306.     First the translations are checked, if they don't match 'y' and 'n'
  307.     are tried.
  308. */
  309. {    char buf[8];
  310.     static char yes[8], no[8];
  311.  
  312.     if (yes[0] == '\0')
  313.     {    strncpy(yes, PSTR("y"), 7);
  314.         strncpy(no, PSTR("n"), 7);
  315.     }
  316.     flush_input();
  317.     getstring(buf,6,TRUE);    /* echo keyboard input */
  318.     strlwr(buf);
  319.     if (!strncmp(buf, no, strlen(no)))
  320.         return(FALSE);
  321.     if (!strncmp(buf, yes, strlen(yes)))
  322.         return(TRUE);
  323.     if (buf[0] == 'n')
  324.         return(FALSE);
  325.     if (buf[0] == 'y')
  326.         return(TRUE);
  327.     return(default_answer == 'y' ? TRUE : FALSE);
  328. }    /* getyesno */
  329.  
  330.  
  331.  
  332. void maybe_force_extension(char *filename, char *extension)
  333. {    /* if user consents to it, change the filename extension. */
  334.     char newname[MAX_PATH];
  335.     if (!has_extension(filename,extension))
  336.     {    strcpy(newname,filename);
  337.         force_extension(newname,extension);
  338.         if (!file_exists(newname))
  339.         {    fprintf(pgpout,PSTR("\nShould '%s' be renamed to '%s' [Y/n]? "),
  340.                 filename,newname);
  341.             if (getyesno('y'))
  342.                 rename(filename,newname);
  343.         }
  344.     }
  345. }    /* maybe_force_extension */
  346.  
  347. char *buildfilename(char *result, char *fname)
  348. /*    Builds a filename with a complete path specifier from the environmental
  349.     variable PGPPATH.
  350. */
  351. {    char *s = getenv(PGPPATH);
  352.  
  353.     if ( s==NULL || strlen(s) > 50) /* undefined, or too long to use */
  354.         s="";
  355.     strcpy(result,s);
  356.     if (strlen(result) != 0)
  357. #ifdef BSLASH
  358.         if (result[strlen(result)-1] != '\\')
  359.             strcat(result,"\\");
  360. #else
  361. #ifdef FSLASH
  362.         if (result[strlen(result)-1] != '/')
  363.             strcat(result,"/");
  364. #else
  365. #ifdef VMS
  366.         if (result[strlen(result)-1] != ']')
  367.             strcat(result,"]");
  368. #endif
  369. #endif
  370. #endif /* Various OS-specific defines */
  371.     strcat(result,fname);
  372.     return(result);
  373. }    /* buildfilename */
  374.  
  375. int build_path(char *path, char *fileName, char *origPath)
  376. /* Build a path for fileName based on origPath */
  377. {    int i, lastSlash = 0;
  378.  
  379. #ifdef BSLASH
  380.     for (i=0; origPath[i]; i++)
  381.         if (origPath[i] == ':' || origPath[i] == '\\')
  382.             lastSlash = i + 1;
  383. #else
  384. #ifdef VMS
  385.     for (i=0; origPath[i]; i++)
  386.         if (origPath[i] == ']')
  387.             lastSlash = i + 1;
  388. #else
  389.     for (i=0; origPath[i]; i++)
  390.         if (origPath[i] == '/')
  391.             lastSlash = i + 1;
  392. #endif
  393. #endif
  394.  
  395.     /* Sanity check: Make sure the path is of legal length */
  396.     if (i>=MAX_PATH)
  397.     {    fprintf(pgpout,PSTR("Path '%s' too long\n"), origPath);
  398.         return(-1);    /* error return */
  399.     }
  400.  
  401.     strncpy(path,origPath,lastSlash);    /* Add path component */
  402.     strcpy(path+lastSlash,fileName);    /* Append filename */
  403.     return(0);    /* normal return */
  404. }    /* build_path */
  405.  
  406.  
  407. void file_to_canon(char *filename)
  408. {    /* Convert filename to canonical form, with slashes as separators */
  409. #ifdef BSLASH
  410.     while (*filename) {
  411.         if (*filename == '\\')
  412.             *filename = '/';
  413.         ++filename;
  414.     }
  415. #endif
  416. }
  417.  
  418.  
  419. void file_from_canon(char *filename)
  420. {    /* Convert filename from canonical to local form */
  421.     /* I think everyone can handle slashes */
  422.     filename = filename;        /* Suppress warning */
  423. }
  424.  
  425.  
  426. FILE *fopenbin(char *name, char *mode)
  427. {
  428. #if !defined(UNIX)
  429.     char mode_b[8];
  430.  
  431.     strcpy(mode_b, mode);
  432.     strcat(mode_b, "b");
  433.     mode = mode_b;
  434. #endif
  435.  
  436. #ifdef VMS
  437.     if (*mode == 'r')
  438.         return(fopen(name, mode, "ctx=stm"));
  439.     else
  440.         return(fopen(name, mode));
  441. #else
  442.     return(fopen(name, mode));
  443. #endif
  444. }
  445.  
  446. FILE *fopentxt(char *name, char *mode)
  447. {
  448. #ifdef VMS
  449.     if (*mode == 'r')
  450.         return(fopen(name, mode, "ctx=stm"));
  451.     else
  452.         return(fopen(name, mode));
  453. #else
  454.     return(fopen(name, mode));
  455. #endif
  456. }
  457.  
  458.  
  459. int copyfile(FILE *f, FILE *g, word32 longcount)
  460. {    /* copy file f to file g, for longcount bytes */
  461.     int count, status = 0;
  462.     do    /* read and write the whole file... */
  463.     {
  464.         if (longcount < (word32) DISKBUFSIZE)
  465.             count = (int)longcount;
  466.         else
  467.             count = DISKBUFSIZE;
  468.         count = fread(textbuf,1,count,f);
  469.         if (count>0)
  470.         {
  471.             if (CONVERSION != NO_CONV)
  472.             {       int i;
  473.                 for (i = 0; i < count; i++)
  474.                     textbuf[i] = (CONVERSION == EXT_CONV) ?
  475.                              EXT_C(textbuf[i]) :
  476.                              INT_C(textbuf[i]);
  477.             }
  478.             if (fwrite(textbuf,1,count,g) != count )
  479.             {   /* Problem: return error value */
  480.                 status = -1;
  481.                 break;
  482.             }
  483.             longcount -= count;
  484.         }
  485.         /* if text block was short, exit loop */
  486.     } while (count==DISKBUFSIZE);
  487.     burn(textbuf);    /* burn sensitive data on stack */
  488.     return(status);
  489. }    /* copyfile */
  490.  
  491. int copyfilepos (FILE *f, FILE *g, word32 longcount, word32 fpos)
  492. /* Like copyfile, but takes a position for file f.  Returns with
  493.  * f and g pointing just past the copied data.
  494.  */
  495. {
  496.     fseek (f, fpos, SEEK_SET);
  497.     return copyfile (f, g, longcount);
  498. }
  499.  
  500.  
  501. #ifndef CANONICAL_TEXT
  502. int copyfile_to_canon (FILE *f, FILE *g, word32 longcount)
  503. {    /* copy file f to file g, for longcount bytes.  Convert to
  504.        canonical form as we go.  f is open in text mode.  Canonical
  505.        form uses crlf's as line separators. */
  506.     int count, status = 0;
  507.     byte c, *tb1, *tb2;
  508.     int i, nbytes;
  509.     do    /* read and write the whole file... */
  510.     {
  511.         if (longcount < (word32) DISKBUFSIZE)
  512.             count = (int)longcount;
  513.         else
  514.             count = DISKBUFSIZE;
  515.         count = fread(textbuf,1,count,f);
  516.         if (count>0)
  517.         {    /* Convert by adding CR before LF */
  518.             tb1 = textbuf;
  519.             tb2 = textbuf2;
  520.             for (i=0; i<count; ++i)
  521.             {       switch (CONVERSION) {
  522.                 case EXT_CONV:
  523.                     c = EXT_C(*tb1++);
  524.                     break;
  525.                 case INT_CONV:
  526.                     c = INT_C(*tb1++);
  527.                     break;
  528.                 default:
  529.                     c = *tb1++;
  530.                 }
  531.                 if (c == '\n')
  532.                     *tb2++ = '\r';
  533.                 *tb2++ = c;
  534.             }
  535.             nbytes = tb2 - textbuf2;
  536.             if (fwrite(textbuf2,1,nbytes,g) != nbytes )
  537.             {   /* Problem: return error value */
  538.                 status = -1;
  539.                 break;
  540.             }
  541.             longcount -= count;
  542.         }
  543.         /* if text block was short, exit loop */
  544.     } while (count==DISKBUFSIZE);
  545.     burn(textbuf);    /* burn sensitive data on stack */
  546.     burn(textbuf2);
  547.     return(status);
  548. }    /* copyfile_to_canon */
  549. #endif
  550.  
  551.  
  552. #ifndef CANONICAL_TEXT
  553. int copyfile_from_canon (FILE *f, FILE *g, word32 longcount)
  554. {    /* copy file f to file g, for longcount bytes.  Convert from
  555.        canonical to local form as we go.  g is open in text mode.  Canonical
  556.        form uses crlf's as line separators. */
  557.     int count, status = 0;
  558.     byte c, *tb1, *tb2;
  559.     int i, nbytes;
  560.     do    /* read and write the whole file... */
  561.     {
  562.         if (longcount < (word32) DISKBUFSIZE)
  563.             count = (int)longcount;
  564.         else
  565.             count = DISKBUFSIZE;
  566.         count = fread(textbuf,1,count,f);
  567.         if (count>0)
  568.         {    /* Convert by removing CR's */
  569.             tb1 = textbuf;
  570.             tb2 = textbuf2;
  571.             for (i=0; i<count; ++i)
  572.             {       switch (CONVERSION) {
  573.                 case EXT_CONV:
  574.                     c = EXT_C(*tb1++);
  575.                     break;
  576.                 case INT_CONV:
  577.                     c = INT_C(*tb1++);
  578.                     break;
  579.                 default:
  580.                     c = *tb1++;
  581.                 }
  582.                 if (c != '\r')
  583.                     *tb2++ = c;
  584.             }
  585.             nbytes = tb2 - textbuf2;
  586.             if (fwrite(textbuf2,1,nbytes,g) != nbytes )
  587.             {   /* Problem: return error value */
  588.                 status = -1;
  589.                 break;
  590.             }
  591.             longcount -= count;
  592.         }
  593.         /* if text block was short, exit loop */
  594.     } while (count==DISKBUFSIZE);
  595.     burn(textbuf);    /* burn sensitive data on stack */
  596.     burn(textbuf2);
  597.     return(status);
  598. }    /* copyfile_from_canon */
  599. #endif
  600.  
  601.  
  602. int copyfiles_by_name(char *srcFile, char *destFile)
  603. /*    Copy srcFile to destFile  */
  604. {
  605.     FILE *f, *g;
  606.     int status = 0;
  607.     long fileLength;
  608.  
  609. #ifdef VMS
  610.     if (((f=fopen(srcFile,"rb","ctx=stm")) == NULL) ||
  611. #else
  612.     if (((f=fopen(srcFile,"rb")) == NULL) ||
  613. #endif
  614.         ((g=fopen(destFile,"wb")) == NULL))
  615.         /* Can't open files */
  616.         return(-1);
  617.  
  618.     /* Get file length and copy it */
  619.     fseek(f,0L,SEEK_END);
  620.     fileLength = ftell(f);
  621.     rewind(f);
  622.     status = copyfile(f,g,fileLength);
  623.     fclose(f);
  624.     fclose(g);
  625.     return(status);
  626. }    /* copyfiles_by_name */
  627.  
  628.  
  629. int make_canonical(char *srcFile, char *destFile)
  630. /*    Copy srcFile to destFile, converting to canonical text form  */
  631. {
  632.     FILE *f, *g;
  633.     int status = 0;
  634.     long fileLength;
  635.  
  636. #ifdef CANONICAL_TEXT
  637.     if (((f=fopen(srcFile,"rb")) == NULL) ||
  638. #else
  639.     if (((f=fopen(srcFile,"r")) == NULL) ||
  640. #endif
  641.         ((g=fopen(destFile,"wb")) == NULL))
  642.         /* Can't open files */
  643.         return(-1);
  644.  
  645.     /* Get file length and copy it */
  646.     fseek(f,0L,SEEK_END);
  647.     fileLength = ftell(f);
  648.     rewind(f);
  649.     CONVERSION = INT_CONV;
  650. #ifdef CANONICAL_TEXT
  651.     status = copyfile(f,g,fileLength);
  652. #else
  653.     status = copyfile_to_canon(f,g,fileLength);
  654. #endif
  655.     CONVERSION = NO_CONV;
  656.     fclose(f);
  657.     fclose(g);
  658.     return(status);
  659. }    /* make_canonical */
  660.  
  661.  
  662. int rename2(char *srcFile, char *destFile)
  663. /*    Like rename() but will try to copy the file if the rename fails.
  664.     This is because under OS's with multiple physical volumes if the
  665.     source and destination are on different volumes the rename will fail */
  666. {
  667.     FILE *f, *g;
  668.     int status = 0;
  669.     long fileLength;
  670.  
  671.     if (rename(srcFile,destFile) == -1)
  672.     {    /* Rename failed, try a copy */
  673. #ifdef VMS
  674.         if (((f=fopen(srcFile,"rb","ctx=stm")) == NULL) ||
  675. #else
  676.         if (((f=fopen(srcFile,"rb")) == NULL) ||
  677. #endif
  678.             ((g=fopen(destFile,"wb")) == NULL))
  679.             /* Can't open files */
  680.             return(-1);
  681.  
  682.         /* Get file length and copy it */
  683.         fseek(f,0L,SEEK_END);
  684.         fileLength = ftell(f);
  685.         rewind(f);
  686.         status = copyfile(f,g,fileLength);
  687.  
  688.         /* Zap source file if the copy went OK, otherwise zap the (possibly
  689.            incomplete) destination file */
  690.         if (status >= 0)
  691.         {    wipeout(f);        /* Zap source file */
  692.             fclose(f);
  693.             remove(srcFile);
  694.             fclose(g);
  695.         }
  696.         else
  697.         {    if (is_regular_file(destFile))
  698.             {    wipeout(g);        /* Zap destination file */
  699.                 fclose(g);
  700.                 remove(destFile);
  701.             } else
  702.                 fclose(g);
  703.             fclose(f);
  704.         }
  705.     }
  706.     return(status);
  707. }
  708.  
  709.  
  710. int readPhantomInput(char *filename)
  711. /* read the data from stdin to the phantom input file */
  712. {    FILE *outFilePtr;
  713.     byte buffer[ 512 ];
  714.     int bytesRead;
  715.  
  716.     if ((outFilePtr = fopen(filename,"wb")) == NULL)
  717.         return(-1);
  718.  
  719. #ifdef MSDOS
  720.     /* Under DOS must set input stream to binary mode to avoid data mangling */
  721.     setmode(fileno(stdin), O_BINARY);
  722. #endif /* MSDOS */
  723.     while ((bytesRead = fread (buffer, 1, 512, stdin)) > 0)
  724.         fwrite (buffer, 1, bytesRead, outFilePtr);
  725.     fclose (outFilePtr);
  726. #ifdef MSDOS
  727.     setmode(fileno(stdin), O_TEXT);    /* Reset stream */
  728. #endif /* MSDOS */
  729.     return(0);
  730. }
  731.  
  732.  
  733. void writePhantomOutput(char *filename)
  734. /* write the data from the phantom output file to stdout */
  735. {    FILE *outFilePtr;
  736.     byte buffer[ 512 ];
  737.     int bytesRead;
  738.  
  739.     /* this can't fail since we just created the file */
  740.     outFilePtr = fopen(filename,"rb");
  741.  
  742. #ifdef MSDOS
  743.     setmode(fileno(stdout), O_BINARY);
  744. #endif
  745.     while ((bytesRead = fread (buffer, 1, 512, outFilePtr)) > 0)
  746.         fwrite (buffer, 1, bytesRead, stdout);
  747.     fclose (outFilePtr);
  748.     fflush(stdout);
  749. #ifdef MSDOS
  750.     setmode(fileno(stdout), O_TEXT);
  751. #endif
  752.  
  753.     /* finally, delete the phantom file */
  754.     wipefile(filename);
  755.     remove(filename);
  756. }
  757.  
  758. /* Return the size from the current position of file f to the end */
  759. word32 fsize (FILE *f)
  760. {
  761.     long fpos = ftell (f);
  762.     long fpos2;
  763.  
  764.     fseek (f, 0L, SEEK_END);
  765.     fpos2 = ftell (f);
  766.     fseek (f, fpos, SEEK_SET);
  767.     return (word32)(fpos2 - fpos);
  768. }
  769.  
  770. /* Return TRUE if file filename looks like a pure text file */
  771. int is_text_file (char *filename)
  772. {
  773.     FILE    *f = fopen(filename,"rb");
  774.     int        i, n, bit8 = 0;
  775.     unsigned char buf[512];
  776.     unsigned char *bufptr = buf;
  777.     unsigned char c;
  778.  
  779.     if (!f)
  780.         return(FALSE);    /* error opening it, so not a text file */
  781.     i = n = fread (buf, 1, sizeof(buf), f);
  782.     fclose(f);
  783.     if (n <= 0)
  784.         return(FALSE);    /* empty file or error, not a text file */
  785.     if (compressSignature(buf) >= 0)
  786.         return(FALSE);
  787.     while (i--)
  788.     {    c = *bufptr++;
  789.         if (c & 0x80)
  790.             ++bit8;
  791.         else /* allow BEL BS HT LF VT FF CR EOF control characters */
  792.             if (c < '\007' || (c > '\r' && c < ' ' && c != '\032'))
  793.                 return(FALSE);    /* not a text file */
  794.     }
  795.     if (strcmp(language, "ru"))
  796.         return(TRUE);
  797.     /* assume binary if more than 1/4 bytes have 8th bit set */
  798.     return(bit8 < n / 4);
  799. } /* is_text_file */
  800.  
  801. void *xmalloc(unsigned size)
  802. {    void *p;
  803.     if (size == 0)
  804.         ++size;
  805.     if ((p = malloc(size)) == NULL)
  806.     {    fprintf(stderr, PSTR("\n\007Out of memory.\n"));
  807.         exitPGP(1);
  808.     }
  809.     return(p);
  810. }
  811.  
  812. /*----------------------------------------------------------------------
  813.  *    temporary file routines
  814.  */
  815.  
  816.  
  817. #define MAXTMPF 8
  818.  
  819. #define    TMP_INUSE    2
  820.  
  821. static struct
  822. {    char path[MAX_PATH];
  823.     int flags;
  824. } tmpf[MAXTMPF];
  825.  
  826. extern char outdir[];
  827. extern char basename[];
  828.  
  829. /*
  830.  * return a unique temporary file name
  831.  */
  832. char *tempfile(int flags)
  833. {
  834.     int i;
  835.     int num = 0;
  836.  
  837.     for (i = 0; i < MAXTMPF; ++i)
  838.         if (tmpf[i].flags == 0)
  839.             break;
  840.     
  841.     if (i == MAXTMPF)
  842.     {    /* message only for debugging, no need for PSTR */
  843.         fprintf(stderr, "\n\007Out of temporary files\n");
  844.         return(NULL);
  845.     }
  846.  
  847.     do
  848.         sprintf(tmpf[i].path, "%s%s.%c%02d",
  849.             (flags & TMP_TMPDIR ? tmpdir : outdir), basename, TMP_EXT, num);
  850.     while (file_exists(tmpf[i].path) && ++num < 100);
  851.  
  852.     if (!file_ok_write(tmpf[i].path))
  853.     {    fprintf(pgpout, PSTR("\n\007Cannot create temporary file '%s'\n"), tmpf[i].path);
  854.         user_error();
  855.     }
  856.  
  857.     if (num == 100)
  858.     {    fprintf(stderr, "\n\007tempfile: cannot find unique name\n");
  859.         return(NULL);
  860.     }
  861.  
  862.     tmpf[i].flags = flags | TMP_INUSE;
  863.     if (verbose)
  864.         fprintf(stderr, "tempfile: created '%s'\n", tmpf[i].path);
  865.     return(tmpf[i].path);
  866. }    /* tempfile */
  867.  
  868. /*
  869.  * remove temporary file, wipe if necessary.
  870.  */
  871. void rmtemp(char *name)
  872. {
  873.     int i;
  874.  
  875.     for (i = 0; i < MAXTMPF; ++i)
  876.         if (tmpf[i].flags && strcmp(tmpf[i].path, name) == 0)
  877.             break;
  878.  
  879.     if (i < MAXTMPF)
  880.     {    if (strlen(name) > 3 && name[strlen(name)-3] == TMP_EXT)
  881.         {    /* only remove file if name hasn't changed */
  882.             if (verbose)
  883.                 fprintf(stderr, "rmtemp: removing '%s'\n", name);
  884.             if (tmpf[i].flags & TMP_WIPE)
  885.                 wipefile(name);
  886.             remove(name);
  887.             tmpf[i].flags = 0;
  888.         } else if (verbose)
  889.             fprintf(stderr, "rmtemp: not removing '%s'\n", name);
  890.     }
  891. }    /* rmtemp */
  892.  
  893. /*
  894.  * make temporary file permanent, returns the new name.
  895.  */
  896. char *savetemp(char *name, char *newname)
  897. {
  898.     int i, overwrite;
  899.     static char buf[MAX_PATH];
  900.  
  901.     if (strcmp(name, newname) == 0)
  902.         return(name);
  903.  
  904.     for (i = 0; i < MAXTMPF; ++i)
  905.         if (tmpf[i].flags && strcmp(tmpf[i].path, name) == 0)
  906.             break;
  907.  
  908.     if (i < MAXTMPF)
  909.     {    if (strlen(name) < 4 || name[strlen(name)-3] != TMP_EXT)
  910.         {    if (verbose)
  911.                 fprintf(stderr, "savetemp: not renaming '%s' to '%s'\n",
  912.                         name, newname);
  913.             return(name);    /* return original file name */
  914.         }
  915.     }
  916.  
  917.     while (file_exists(newname))
  918.     {
  919.         if (is_regular_file(newname))
  920.         {    fprintf(pgpout,PSTR("\n\007Output file '%s' already exists.  Overwrite (y/N)? "),newname);
  921.             overwrite = getyesno('n');
  922.         }
  923.         else
  924.         {    fprintf(pgpout,PSTR("\n\007Output file '%s' already exists.\n"),newname);
  925.             overwrite = FALSE;
  926.         }
  927.  
  928.         if (!overwrite)
  929.         {    fprintf(pgpout, PSTR("\nEnter new file name: "));
  930.             getstring(buf, MAX_PATH - 1, TRUE);
  931.             if (buf[0] == '\0')
  932.                 return(NULL);
  933.             newname = buf;
  934.         }
  935.         else
  936.             remove(newname);
  937.     }
  938.     if (verbose)
  939.         fprintf(stderr, "savetemp: renaming '%s' to '%s'\n", name, newname);
  940.     if (rename2(name, newname) < 0)
  941.     {    /* errorLvl = UNKNOWN_FILE_ERROR; */
  942.         return(NULL);
  943.     }
  944.     if (i < MAXTMPF)
  945.         tmpf[i].flags = 0;
  946.     return(newname);
  947. }    /* savetemp */
  948.  
  949. /*
  950.  * like savetemp(), only make backup of destname if it exists
  951.  */
  952. int savetempbak(char *tmpname, char *destname)
  953. {
  954.     char bakpath[MAX_PATH];
  955.  
  956.     if (strcmp(destname, SCRATCH_KEYRING_PATH) == 0 ||
  957.             is_tempfile(destname))
  958.         remove(destname);
  959.     else
  960.     {    if (file_exists(destname))
  961.         {
  962.             strcpy(bakpath, destname);
  963.             force_extension(bakpath, BAK_EXTENSION);
  964.             remove(bakpath);
  965.             if (rename(destname, bakpath) == -1)
  966.                 return(-1);
  967.         }
  968.     }
  969.     if (savetemp(tmpname, destname) == NULL)
  970.         return(-1);
  971.     return(0);
  972. }
  973.  
  974. /*
  975.  * remove all temporary files and wipe them if necessary
  976.  */
  977. void cleanup_tmpf(void)
  978. {
  979.     int i;
  980.  
  981.     for (i = 0; i < MAXTMPF; ++i)
  982.         if (tmpf[i].flags)
  983.             rmtemp(tmpf[i].path);
  984. }    /* cleanup_tmpf */
  985.